#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <cstdlib>
#include <mysql/mysql.h>

namespace ns_mysql
{
    enum class STATU
    {
        OK,
        NOT_INIT,
        INIT_ERROR,
        INIT_SUCCESS,
        CONNECTED,
    };
    static const int default_init_cnt = 3;
    class MySQL
    {
    private:
        MYSQL *_my;
        STATU _statu;
        int _init_cnt;
        int _conn_cnt;

    private:
        bool RetryConnect(const std::string &host,
                          const std::string &user,
                          const std::string &password,
                          const std::string &database,
                          unsigned int port,
                          const std::string &unix_socket = "",
                          unsigned int clientflag = 0)
        {
            if (_statu != STATU::INIT_SUCCESS)
                return false;
            while (mysql_real_connect(_my,
                                      host.c_str(),
                                      user.c_str(),
                                      password.c_str(),
                                      database.c_str(),
                                      port, unix_socket.c_str(),
                                      clientflag) == nullptr &&
                   _conn_cnt)
            {
                // 重连
                --_conn_cnt;
            }
            if (_conn_cnt == 0)
            {
                // TODO,之后可以改成日志
                std::cerr << "MySQL Connect error" << std::endl;
                return false;
            }
            //这里直接使用默认的重试次数即可
            _conn_cnt = default_init_cnt;
            _statu = STATU::CONNECTED;
            return true;
        }
        void RetryInit()
        {
            while (_my == nullptr && _init_cnt)
            {
                _my = mysql_init(nullptr);
                --_init_cnt;
            }
            if (_init_cnt == 0 && _my == nullptr)
            {
                _statu = STATU::INIT_ERROR;
                abort();
            }
            _statu = STATU::INIT_SUCCESS;
        }

    public:
        MySQL(int init_cnt = default_init_cnt, int con_cnt = default_init_cnt)
            : _my(nullptr),
              _statu(STATU::NOT_INIT),
              _init_cnt(init_cnt),
              _conn_cnt(con_cnt)
        {
            RetryInit();
            _init_cnt = init_cnt;
        }

        bool ConnectMysql(const std::string &host,
                          const std::string &user,
                          const std::string &password,
                          const std::string &database,
                          unsigned int port,
                          const std::string &unix_socket = "",
                          unsigned int clientflag = 0)
        {
            return RetryConnect(host, user, password, database, port, unix_socket, clientflag);
        }
        ~MySQL()
        {
            mysql_close(_my);
        }

        STATU Statu()
        {
            return _statu;
        }
    };
}
